首先,讓我們了解Image組件的四種加載方式:
靜態圖片:本地圖片。
由於這些圖片已整合於應用程式包中,加載速度極快,性能很好。另外也建議對圖片都進行壓縮,以降低整體應用包的大小。
<Image source={require('./my-icon.png')} />
網路圖片: 動態加載的圖片,通常是透過網路請求去拿。
與靜態圖片不同,網路圖片一定要給其寬高。這是因為圖片下載前,React Native無法得知圖片寬高,所以會將圖片寬高預設為0,若不指定寬高,圖片將無法正確顯示。
<Image source={{uri: 'https://reactjs.org/logo-og.png'}}
style={{width: 400, height: 400}} />
要注意的是,這裡要使用uri
而非較常見的url
。而且有個雷點,如果打成url,在iOS上能正常顯示,但是Android不行。所以如果在開發過程中只測試了iOS,可能會導致最後上線Android出現問題。
混合圖片: 指的是將圖片放在原生應用的資料夾中 (Xcode 的 asset 、 Android 的 drawable )。
IOS
<Image
source={{ uri: 'app_icon' }}
style={{ width: 40, height: 40 }}
/>
Android
<Image
source={{ uri: 'asset:/app_icon.png' }}
style={{ width: 40, height: 40 }}
/>
這種做法在混合開發的情境中比較會出現,也就是專案是一部分React Native,一部分原生。
利用這種方法可以讓圖片在同一位置,有助於節省資源。但缺點是React Native團隊與原生團隊之間的溝通成本會增加,可能需要更多的協調和調整。此外,兩者的更新和迭代速度可能不同,容易導致一些版本差異問題。是否要用這種方式,端看你或你的團隊怎麼權衡圖片複用效益和溝通、維護成本。
Base64 圖片。
Base64 是將二進制資料轉換成由 64 個可見字符組成的字串的編碼方式。Base64 圖片就是將圖片以 Base64 格式編碼。
<Image source={{ uri: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAAAAAAAD' }} />
如所見,Base64 圖片並非一般的圖片地址,而是一長串由字母、數字和符號組成的字串。一般我們所見的圖片檔案,如 .jpg、.png,都是以二進制格式存在的。但當圖片進行 Base64 編碼後,它會轉變成一段由字母、數字和符號組成的字串。
它的優點在於,Base64 編碼的圖片解析速度快,能迅速展示圖像。缺點是,最終打包後 Base64 圖片存在 Bundle 文件中,會導致Bundle體積變大,進而影響到Bundle下載速度,可能會拖慢 React Native 頁面的加載速度。
通常建議只在體積較小的圖片上使用。
為什麼是uri,而不是url呢?URI
(Uniform Resource Identifier) 和 URL
(Uniform Resource Locator)其實有不同的含義,URI
是一個更廣泛的概念,可以說URL只是URI的一個子集。
在前面的例子,source={{ uri: 'app_icon' }}
中,app_icon
只是一個圖片名稱(URN),也並非URL。因此,React Native 選擇使用uri
來表示滿合理的,其涵蓋的範圍較廣。
為何不在所有情況都自動指定圖片尺寸?
前面有提到,網路圖片在 React Native 中必須明確指定寬高。不過有Web開發經驗的開發者應該知道,在Web中,如果不給網路圖片指定寬高,圖片還是能正常顯示。瀏覽器處理時會先給0x0,然後圖片下載完後再依實際圖片寬高渲染圖片。
那麼,為什麼 React Native 不選擇這種方式,這樣不是更方便嗎?
這是個好問題,在React Native 官網也有特別提到,若用瀏覽器那種方式,圖片加載過程中容易出現頁面跳動。所謂頁面跳動,大家應該有經驗,有時候你想點某個按鈕,結果點下去時頁面跳了一下 導致你點到了別的地方, 這樣的使用體驗顯然不佳。React Native 想要避免這個問題,所以要求網路圖片要明確指定寬高,確保更穩定,也是一種是以用戶體驗為優先的設計。
圖片預加載
有時候我們希望將網路圖片先下載下來,之後用戶看到時就是會從緩存加載的圖片,圖片展示速度會快很多。我們可以用Image的prefetch方法來達成
useEffect(() => {
Image.prefetch('https://example.com/path/to/image.jpg');
}, []);
獲取圖片寬高
使用Image.getSize()
import { Image } from 'react-native'
Image.getSize(imageUrl,(width,height)=>{
console.log('寬度:',width,'高度:',height)
})
圖片增加模糊濾鏡
React Native已經幫我們做好了,只要加上blurRadius屬性即可。
blurRadius接受一個數字,代表模糊的程度。數值越高,模糊效果越強。
<Image
source={{ uri: 'https://example.com/my-image.jpg' }}
style={{ width: 100, height: 100 }}
blurRadius={10}
/>
用神奇的tintColor
改變圖片顏色
依不同狀態改變icon顏色的需求是很常見的,如果不知道tintColor,你可能會用兩張不同顏色的圖片來開發這個需求。但其實Image組件的style中有一個tintColor屬性,能讓我們輕鬆的調整圖片顏色。
範例:
首先,這是我們的原始黑色圖片
接著,透過設定tintColor為'green'
最後,這張圖片就變成了綠色。(實際上,tintColor是將圖片中非透明部分染色)
Android大圖問題
在圖片的處理上,iOS平台表現得相對穩定,Android平台卻較容易遇到些小問題。
筆者曾經遇到一個需求:APP中有一頁要用一張非常大的圖片展示。當我完成開發並在iOS上測試後,一切看起來都很完美。然後直覺圖片的展示在Android應該也是相似的,於是我就沒有特地測試Android,直接交給QA進行測試。結果QA就回饋表示在Android上圖片顯得非常模糊。
這是因為Android在圖片處理上有所限制,尤其是大圖片。
這裡做個範例,這是一張寬度375 高度5700的圖,左邊Android 右邊IOS,可以看到,Android平台上的圖片遠不如iOS清晰。
這問題主要有兩種解決方法:
筆者後來是用第一種方法處理的,也是較為建議的方法,只有在真的沒有辦法時,才考慮使用第二種方法。因為使用WebView即意味著放棄原生的效能優勢。
FastImage:此套件基於 SDWebImage (iOS) 和 Glide (Android) 開發,可以帶來更出色的性能和效果。
AutoHeightImage:
在 React Native Image 組件中,要使圖片在特定寬度內完整展現,我們需要設置 resizeMode
為 stretch
。但這種方式可能會改變圖片的原始比例,影響顯示效果。
使用 AutoHeightImage 可以輕鬆解決這個問題。只需指定圖片寬度,此套件就會自動調整高度,保持圖片的原始比例。
Image組件在React Native中,使用上相對直觀,但其實它很多細節是會直接影響到應用的性能和使用體驗,所以正確暸解和掌握Image組件的使用方法是相當重要的。